using System;
using Gj;
using UnityEngine;

public class CommandPart : BasePart, CastPart.Notice, MovePart.Notice
{
    public enum ProcessResult
    {
        success,
        doing,
        cancel,
        error
    }

    private CastPart _castPart;

    private MovePart _movePart;
    private Notice _notice;
    private Control _self;
    private bool casting;

    private Action<ProcessResult> end;
    private bool moving;
    private Action next;
    private bool waiting;

    public CastPart CastPart
    {
        get
        {
            if (_castPart == null) _castPart = GetComponent<CastPart>();
            return _castPart;
        }
    }

    public MovePart MovePart
    {
        get
        {
            if (_movePart == null) _movePart = GetComponent<MovePart>();
            return _movePart;
        }
    }

    /// <summary>
    ///     技能准备中操作
    /// </summary>
    /// <param name="skill"></param>
    void CastPart.Notice.Ready(Skill skill)
    {
        Lock();
        casting = true;
    }

    /// <summary>
    ///     技能准备中操作
    /// </summary>
    /// <param name="skill"></param>
    void CastPart.Notice.Stop(Skill skill)
    {
        casting = false;
        UnLock();
        Cancel();
    }

    /// <summary>
    ///     技能开始后操作
    /// </summary>
    /// <param name="skill"></param>
    void CastPart.Notice.Start(Skill skill)
    {
        Lock();
        if (moving) MovePart.Cancel();
        casting = true;
    }

    /// <summary>
    ///     技能取消后操作
    /// </summary>
    /// <param name="skill"></param>
    void CastPart.Notice.Cancel(Skill skill)
    {
        casting = false;
        UnLock();
        Cancel();
    }

    /// <summary>
    ///     技能结束后操作
    /// </summary>
    /// <param name="skill"></param>
    void CastPart.Notice.End(Skill skill)
    {
        casting = false;
        UnLock();
        End();
    }

    void MovePart.Notice.StopWithError()
    {
        End(ProcessResult.cancel);
    }

    void MovePart.Notice.StopWithSuccess()
    {
        End();
    }

    /// <summary>
    ///     初始化
    /// </summary>
    public void Init(Control obj)
    {
        _self = obj;
        if (CastPart != null) CastPart.SetOther(this);
        if (MovePart != null) MovePart.Set(this);
    }

    public void Set(Notice notice)
    {
        _notice = notice;
    }

    public bool IsDoing()
    {
        return end != null;
    }

    /// <summary>
    ///     流程器锁定
    /// </summary>
    private void Lock()
    {
        if (_notice != null) _notice.Lock();
    }

    /// <summary>
    ///     流程器解锁
    /// </summary>
    private void UnLock()
    {
        if (_notice != null) _notice.UnLock();
    }

    /// <summary>
    ///     外部执行刷新
    /// </summary>
    public void Refresh()
    {
        if (waiting && next != null)
        {
            waiting = false;
            next();
        }

        // move在next后，确保先判断释放
        if (moving) MovePart.OnUpdate();
    }


    /// <summary>
    ///     设定下次刷新执行函数
    /// </summary>
    /// <param name="action"></param>
    public void Next(Action action)
    {
        next = action;
        waiting = true;
    }

    /// <summary>
    ///     施放初始化
    /// </summary>
    /// <param name="skill"></param>
    public void Cast(Skill skill, Action<ProcessResult> cb)
    {
        if (Begin(cb))
        {
            if (CastPart == null)
                Cancel();
            else
                Cast(skill);
        }
    }

    /// <summary>
    ///     施放执行
    /// </summary>
    /// <param name="skill"></param>
    private void Cast(Skill skill)
    {
        if (!_self.IsExist()) return;
        var result = CastPart.Cast(skill);
        switch (result)
        {
            case CastResult.NeedError:
                Error("skill need error");
                break;
            case CastResult.Casting:
            case CastResult.TimeError:
            case CastResult.PowerError:
                Next(() => { Cast(skill); });
                break;
        }
    }

    /// <summary>
    ///     指定目标施放初始化
    /// </summary>
    /// <param name="skill"></param>
    /// <param name="target"></param>
    public void CastTarget(Skill skill, Life target, Action<ProcessResult> cb)
    {
        if (Begin(cb))
        {
            if (CastPart == null)
                Cancel();
            else
                CastTarget(skill, target);
        }
    }

    /// <summary>
    ///     指定目标施放初始化
    /// </summary>
    /// <param name="skill"></param>
    /// <param name="target"></param>
    public void MoveCastTarget(Skill skill, Life target, Action<ProcessResult> cb)
    {
        if (Begin(cb))
        {
            if (MovePart == null || CastPart == null)
            {
                Cancel();
            }
            else
            {
                if (!CastPart.IsInCastRange(target.GetPosition()))
                {
                    moving = true;
                    MovePart.MoveTarget(target);
                }

                CastTarget(skill, target);
            }
        }
    }

    /// <summary>
    ///     指定目标施放执行
    /// </summary>
    /// <param name="skill"></param>
    /// <param name="target"></param>
    private void CastTarget(Skill skill, Life target)
    {
        if (!_self.IsExist()) return;
        var result = CastPart.Cast(skill, target);
        switch (result)
        {
            case CastResult.NeedError:
                Error("skill need error");
                break;
            case CastResult.TargetRelationError:
                Error("skill target relation error");
                break;
            case CastResult.TargetStatusError:
                Cancel();
                break;
            case CastResult.RangeError:
                if (moving)
                    Next(() => { CastTarget(skill, target); });
                else
                    Cancel();

                break;
            case CastResult.Casting:
            case CastResult.TimeError:
            case CastResult.PowerError:
                Next(() => { CastTarget(skill, target); });
                break;
        }
    }

    /// <summary>
    ///     指定坐标施放初始化
    /// </summary>
    /// <param name="skill"></param>
    /// <param name="position"></param>
    public void CastPosition(Skill skill, Vector3 position, Action<ProcessResult> cb)
    {
        if (Begin(cb))
        {
            if (CastPart == null)
                Cancel();
            else
                CastPosition(skill, position);
        }
    }

    /// <summary>
    ///     指定坐标施放初始化
    /// </summary>
    /// <param name="skill"></param>
    /// <param name="position"></param>
    public void MoveCastPosition(Skill skill, Vector3 position, Action<ProcessResult> cb)
    {
        if (Begin(cb))
        {
            if (MovePart == null || CastPart == null)
            {
                Cancel();
            }
            else
            {
                moving = true;
                MovePart.MovePosition(position);
                CastPosition(skill, position);
            }
        }
    }

    /// <summary>
    ///     指定坐标施放执行
    /// </summary>
    /// <param name="skill"></param>
    /// <param name="position"></param>
    private void CastPosition(Skill skill, Vector3 position)
    {
        if (!_self.IsExist()) return;
        var result = CastPart.Cast(skill, position);
        switch (result)
        {
            case CastResult.NeedError:
                Error("skill need error");
                break;
            case CastResult.RangeError:
                if (moving)
                    Next(() => { CastPosition(skill, position); });
                else
                    Cancel();

                break;
            case CastResult.Casting:
            case CastResult.TimeError:
            case CastResult.PowerError:
                Next(() => { CastPosition(skill, position); });
                break;
        }
    }

    public void MoveTarget(UnityObject target, Action<ProcessResult> cb)
    {
        if (Begin(cb))
        {
            if (MovePart == null)
            {
                Cancel();
            }
            else
            {
                moving = true;
                MovePart.MoveTarget(target);
            }
        }
    }

    public void MovePosition(Vector3 position, Action<ProcessResult> cb)
    {
        if (Begin(cb))
        {
            if (MovePart == null)
            {
                Cancel();
            }
            else
            {
                moving = true;
                MovePart.MovePosition(position);
            }
        }
    }

    /// <summary>
    ///     开始执行并检查是否可以执行
    /// </summary>
    /// <param name="cb"></param>
    /// <returns></returns>
    private bool Begin(Action<ProcessResult> cb)
    {
        if (IsDoing())
        {
            cb(ProcessResult.doing);
            return false;
        }

        end = cb;
        // 初始化
        next = null;
        return true;
    }

    /// <summary>
    ///     成功结束
    /// </summary>
    private void End()
    {
        End(ProcessResult.success);
    }

    /// <summary>
    ///     结束执行,执行回调
    /// </summary>
    /// <param name="result"></param>
    private void End(ProcessResult result)
    {
        if (moving)
        {
            moving = false;
            MovePart.Cancel();
        }

        if (end != null)
        {
            end(result);
            end = null;
            next = null;
        }
    }

    /// <summary>
    ///     执行错误
    /// </summary>
    private void Error(string message)
    {
        if (casting)
            CastPart.CancelCast();
        else
            End(ProcessResult.error);
    }

    /// <summary>
    ///     提供外部取消当前施放接口
    /// </summary>
    public void Cancel()
    {
        if (casting)
            CastPart.CancelCast();
        else
            End(ProcessResult.cancel);
    }

    /// <summary>
    ///     AI命令执行通知
    /// </summary>
    public interface Notice
    {
        void Lock();
        void UnLock();
    }
}